//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	EnumerableExts.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;

namespace Smart
{
	[Localizable(false)]
	[DebuggerStepThrough]
	public static class EnumerableExts
	{
		/// <summary>
		/// Adds <paramref name="values"/> to <paramref name="hashSet"/>
		/// </summary>
		public static void AddRange<TValueType>(this HashSet<TValueType> hashSet, IEnumerable<TValueType> values)
		{
			foreach (var value in values)
				hashSet.Add(value);
		}

		/// <summary>
		/// Create groups
		/// </summary>
		public static List<TItemType> CollapseInGroups<TItemType, TGroupType>(this IEnumerable<TItemType> sourceItems, int maxResultItemCount, int maxGroupSize, Func<TGroupType> groupCreator)
			where TItemType : class
			where TGroupType : TItemType, IList<TItemType>
		{
			if (sourceItems == null)
				return null;

			var queries = new List<TItemType>(sourceItems.Where(queryItem => queryItem != null));

			if (queries.Count == 0)
				return null;

			while (queries.Count > maxResultItemCount)
			{
				var tmp = new List<TItemType>((queries.Count / maxGroupSize) + 1);

				for (int I = 0, ICnt = queries.Count; I < ICnt; I += maxGroupSize)
				{
					if (I + maxGroupSize - 1 < ICnt)
					{
						var group = groupCreator();

						for (var J = 0; J < maxGroupSize; J++)
							group.Add(queries[I + J]);

						tmp.Add(group);
					}
					else
					{
						for (var J = I; J < ICnt; J++)
							tmp.Add(queries[J]);
					}
				}

				queries.Clear();
				queries = tmp;
			}

			return queries;
		}

		/// <summary>
		/// Create groups
		/// </summary>
		public static List<TItemType> CollapseInGroups<TItemType, TGroupType>(this IEnumerable<TItemType> sourceItems, int maxResultItemCount, int maxGroupSize, Func<TGroupType> groupCreator, Action<TGroupType, TItemType> groupAdder)
			where TItemType : class
			where TGroupType : TItemType
		{
			if (sourceItems == null)
				return null;

			var queries = new List<TItemType>(sourceItems.Where(queryItem => queryItem != null));

			if (queries.Count == 0)
				return null;

			while (queries.Count > maxResultItemCount)
			{
				var tmp = new List<TItemType>((queries.Count / maxGroupSize) + 1);

				for (int I = 0, ICnt = queries.Count; I < ICnt; I += maxGroupSize)
				{
					if (I + maxGroupSize - 1 < ICnt)
					{
						var group = groupCreator();

						for (var J = 0; J < maxGroupSize; J++)
							groupAdder(group, queries[I + J]);

						tmp.Add(group);
					}
					else
					{
						for (var J = I; J < ICnt; J++)
							tmp.Add(queries[J]);
					}
				}

				queries.Clear();
				queries = tmp;
			}

			return queries;
		}

		/// <summary>
		/// Convert array <paramref name="values"/> to string delimited by ", "
		/// </summary>
		public static string CastToString<TValueType>(this IEnumerable<TValueType> values)
		{
			return CastToString(values, ", ", value => value.SToStr(string.Empty));
		}

		/// <summary>
		/// Convert array <paramref name="values"/> to string delimited by <paramref name="delimiter"/>
		/// </summary>
		public static string CastToString<TValueType>(this IEnumerable<TValueType> values, string delimiter)
		{
			return CastToString(values, delimiter, value => value.SToStr(string.Empty));
		}

		/// <summary>
		/// Convert array <paramref name="values"/> to string delimited by <paramref name="delimiter"/> using <paramref name="converter"/>
		/// </summary>
		public static string CastToString<TValueType>(this IEnumerable<TValueType> values, string delimiter, Func<TValueType, string> converter)
		{
			return values == null ? string.Empty : string.Join(delimiter, values.Select(converter).ToArray());
		}

		/// <summary>
		/// Return enumerable values hash code
		/// </summary>
		public static string GetValuesHashCodeX<TValueType>(this IEnumerable<TValueType> enumerable)
			where TValueType : class
		{
			var hash = 0;

			if (enumerable != null)
			{
				if (typeof(TValueType) == typeof(string))
				{
					var comparer = StringComparer.OrdinalIgnoreCase;

					foreach (var value in enumerable)
						hash = hash ^ (value != null ? comparer.GetHashCode((string)(object)value) : 0);
				}
				else
				{
					foreach (var value in enumerable)
						hash = hash ^ (value != null ? value.GetHashCode() : 0);
				}
			}

			return hash.ToStringX();
		}
	}
}